`include "defines.svh"
`include "axi_defines.svh"
`include "cache_defines.svh"

module icache(
    input         reset,
    input         clk,
    input  word_t debug_pc,

    // AXImaster <-> AXIcache
    input   logic  arvalid,
    input   word_t araddr,
    output  logic  arready,

    input   logic  rready,
    output  word_t rdata,
    output  resp_t rresp,
    output  logic  rvalid,


    // AXIcache <-> AXIslave
    output logic  arvalid_o,
    output word_t araddr_o,
    input  logic  arready_o,

    output logic  rready_o,
    input  word_t rdata_o,
    input  resp_t rresp_o,
    input  logic  rvalid_o
);
    cache_t cache;
    cstate_t cstate;
    addr_t araddr_r;
    logic hit0,hit1;
    logic replace_way; 


    logic ar_shake,r_shake;
    assign ar_shake = arvalid && arready;
    assign r_shake = rvalid && rready;

    logic ar_shake_o,r_shake_o;
    assign ar_shake_o = arvalid_o && arready_o;
    assign r_shake_o = rvalid_o && rready_o;
    always_ff @(posedge clk) begin
        case(cstate) 
            C_IDLE: begin
                arready <= `ON;
                if (ar_shake) begin
                    araddr_r <= araddr;
                    cstate <= LOOKUP;
                    arready <= `OFF;
                end
            end

            LOOKUP: begin
                if(hit0 || hit1) begin
                    rvalid <= `ON;
                    if(r_shake) begin
                        rvalid <= `OFF;
                        cstate <= C_IDLE;
                    end
                end else begin
                    cstate <= MISS;
                end
            end
            MISS: begin
                // 如果需要写回牺牲行，直接抛弃即可
                if(~replace_way) begin 
                    cache.set0[araddr_r.index].valid <= `OFF;
                end else if(replace_way) begin
                    cache.set1[araddr_r.index].valid <= `OFF;
                end
                araddr_o <= araddr_r;
                arvalid_o <= `ON;
                if(ar_shake_o) begin
                    arvalid_o <= `OFF;
                    cstate <= READ_ALO;
                end
            end

            READ_ALO: begin
                rready_o <= `ON;
                if(r_shake_o & ~replace_way) begin
                    rready_o <= `OFF;
                    cache.set0[araddr_r.index].valid <= `ON;
                    cache.set0[araddr_r.index].tag <= araddr_r.tag;
                    cache.set0[araddr_r.index].data <= rdata_o;
                    rdata  <= rdata_o;
                    cstate <= C_IDLE;
                end else if(r_shake_o & replace_way) begin
                    rready_o <= `OFF;
                    cache.set1[araddr_r.index].valid <= `ON;
                    cache.set1[araddr_r.index].tag <= araddr_r.tag;
                    cache.set1[araddr_r.index].data <= rdata_o;
                    rdata  <= rdata_o;
                    cstate <= C_IDLE;
                end
            end
            default: begin
                cstate <= C_IDLE;
            end
        endcase
    end
    

    // hit或者读分配时准备rdata
    always_comb begin
        hit0 = cache.set0[araddr_r.index].valid && (cache.set0[araddr_r.index].tag == araddr_r.tag);
        hit1 = cache.set1[araddr_r.index].valid && (cache.set1[araddr_r.index].tag == araddr_r.tag);
        if (hit0) begin
            rdata = cache.set0[araddr_r.index].data;
        end else if (hit1) begin
            rdata = cache.set1[araddr_r.index].data;
        end else begin
            rdata = `NULL;
        end
    end

endmodule
